#include "stdafx.h"
#include "CppUnitTest.h"

#include "System/Base/String.h"
#include "System/Utility/Testing.h"
#include "System/Base/Exceptions.h"
#include "System/Base/Range.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace Native::System;
using namespace Native { namespace System::Utility;

namespace TestNativeSystem
{
    TEST_CLASS(String_Tester)
    {
    public:
        wstring _wide_string;
        mstring _multi_string;
        CString _base;

        String_Tester() :
            _wide_string(L"1234"),
            _multi_string("1234"),
            _base(L"base")
        {}

        TEST_METHOD(String_EqualTo)
        {
            UEquivalentTester::CheckByEqualTo<CString>(
                dynamic_cast<IEqualTo<CString>*>(&_base),
                CString(L"contrast"),
                false);
        }

        TEST_METHOD(String_Construct)
        {
            UConstructorTester::CheckByEqualTo<CString>(_base);
        }

        TEST_METHOD(String_ConstructDefault)
        {
            CString string;

            Assert::AreEqual(string.ToCString(), L"");
        }

        TEST_METHOD(String_ConstructedByMultiByteString)
        {
            CString string(_multi_string);

            Assert::AreEqual(string.ToString(), _wide_string);
        }

        TEST_METHOD(String_GetContentLength)
        {
            CString string1(_wide_string);
            CString string2;

            Assert::AreEqual(string1.Length(), wstring(_wide_string).length());
            Assert::AreEqual(string2.Length(), 0u);
        }

        TEST_METHOD(String_GetSubstringWithoutException)
        {
            CString string(L"0123456789");

            Assert::AreEqual(string.Substring(0, 5).ToString(), wstring(L"01234"));
            Assert::AreEqual(string.Substring(4).ToString(), wstring(L"456789"));
            Assert::AreEqual(string.Substring(4, 20).ToString(), wstring(L"456789"));
            Assert::AreEqual(string.Substring(4, 6).ToString(), wstring(L"456789"));
            Assert::AreEqual(string.Substring(10).ToString(), wstring(L""));
            Assert::AreEqual(string.Substring(0).ToString(), wstring(L"0123456789"));
        }

        TEST_METHOD(String_GetSubstringLocationIsOutOfRange)
        {
            function<void(void)> throw_exception = [&] {
                CString string(L"0123456789");

                string.Substring(11);
            };

            Assert::ExpectException<CException>(throw_exception);
        }

        TEST_METHOD(String_SplitString)
        {
            CString string1(L"01,23,45");
            CString string2(L"01,23,45,");
            CString string3(L",,");
            CString string4(L",");
            CString string5(EMPTY_STRING);
            CString string6(L"01");

            Assert::AreEqual(string1.Split(L',').size(), 3u);
            Assert::AreEqual(string2.Split(L',').size(), 4u);
            Assert::AreEqual(string3.Split(L',').size(), 3u);
            Assert::AreEqual(string4.Split(L',').size(), 2u);
            Assert::AreEqual(string5.Split(L',').size(), 0u);
            Assert::AreEqual(string6.Split(L',').size(), 1u);
        }

        TEST_METHOD(String_ToUpperOrLower)
        {
            CString string(L"TestABCd123");

            Assert::AreEqual(string.ToUpper().ToCString(), L"TESTABCD123");
            Assert::AreEqual(string.ToLower().ToCString(), L"testabcd123");
        }

        TEST_METHOD(String_GetOneCharacter)
        {
            CString string(L"01");

            Assert::AreEqual(string[0], L'0');
            Assert::AreEqual(string[1], L'1');

            function<void(void)> throw_exception = [] {
                CString string(L"01");
                string[3];
            };

            Assert::ExpectException<CException>(throw_exception);
        }

        TEST_METHOD(String_FindKeyword)
        {
            CString testee(L"TestABCd123");

            Assert::AreEqual(testee.Find(L"ABC"), 4u);
            Assert::AreEqual(testee.Find(L"X"), CString::MISS);
        }

        TEST_METHOD(String_Compare)
        {
            CString string("50");

            Assert::IsTrue(string == CString(L"50"));
            Assert::IsFalse(string != CString(L"50"));
            Assert::IsTrue(string > CString(L"20"));
            Assert::IsFalse(string < CString(L"50"));
            Assert::IsFalse(string <= CString(L"20"));
            Assert::IsTrue(string >= CString(L"50"));
        }

        TEST_METHOD(String_TrimString)
        {
            CString string1(L"\t\t 12345 \n");

            CString string2 = string1.TrimLeft(L'\t');
            Assert::AreEqual(string2.ToString(), wstring(L" 12345 \n"));

            CString string3 = string2.TrimLeft(L' ');
            Assert::AreEqual(string3.ToString(), wstring(L"12345 \n"));

            CString string4 = string3.TrimRight(L'\n');
            Assert::AreEqual(string4.ToString(), wstring(L"12345 "));

            CString string5 = string4.TrimRight(L' ');
            Assert::AreEqual(string5.ToString(), wstring(L"12345"));
        }
    };
}